上一篇我們建立了 gateway ,也把 Task Service 安裝了 federation 的 dependency
接著我們建立 User Service 和 Message Service,也都需要安裝 federation
之後在 User Service 寫一個 Create User 的 API
root
├── services
│ ├── task (port: 4002)
│ ├── user (port: 4001)
│ └── message (port: 4003)
└── gateway (port: 4000)
根據之前的情境
一個 Task 會由一個 User 所建立
一個 User 可以有多的 Task
Task 必須與 User 有所關聯,所以我們在 Task 中會新增一個 UserId 的欄位
使用 @key(fields: "_id")
directive 設定 User 要接收什麼欄位,這邊以 _id 為例子
在 model 中使用 @Directive 設定
@Directive(`@key(fields: "_id")`)
export class User extends Document {
@Field(() => ID)
_id: string;
}
type User @key(fields: "_id") {
_id: ID!
name: String!
}
在 resolver 中還有另一個方法 resolveReference
,當有相關的資源要使用 User 的實體時,Apollo Gateway 便能使用它
注意的是要在 resolveReference
加上 @ResolveReference
decorator
@ResolveReference()
resolveReference(reference: { __typename: string; _id: string }) {
return this.usersService.findById(reference._id);
}
使用 extend
來標記 User
在 Task 中新增一個 user 的 model ,指定要 extend
的欄位
@Directive('@extends')
@Directive(`@key(fields: "_id")`)
@ObjectType()
export class User {
@Directive('@external')
@Field(() => ID)
_id: string;
}
extend type User @key(fields: "id") {
id: ID! @external
}
接著在 Resolver 中寫一個解析欄位物件的一個方法
@ResolveField(() => User)
user(@Parent() task: Task) {
return { __typename: 'User', _id: task.userId };
}
以上我們就完成了在 gateway 中能利用 Task 的 userId ,到 User Service 中查詢 User 並回傳給 Task Service ,最終根據 Schema 的格式回傳給 Client side
:::warning
在開始測試前,請讀者先將之前的資料先全部清除,之前的 Task 並沒有 userId 的欄位,所以無法查出 User 物件
:::
我們直接在 http://localhost:4000/graphql gateway 上做測試
先建立一個 User
mutation {
createUser(userData: { name: "JavaScript" }) {
_id
name
}
}
接著建立 Task
這邊與之前不一樣得部分是多了一個 userId ,如果剛剛的 User 回傳的 _id 沒有紀錄,請讀者到資料庫去找一下吧!
回傳時,我們也能取得 User 的物件
mutation {
createTask(taskData: {
title: "THE THING TO DO TODAY",
content: "THE THING Content"
userId: "5f840e6de88fe979392f010c"
}) {
_id
title
content
user {
name
_id
}
}
}
最後使用查詢找出剛剛建立的 Task
query {
todoTasks {
tasks {
user {
name
_id
}
content
title
}
}
}
完美!!!!